package com.bub.pay.openservice.aop;

import com.alibaba.fastjson.JSON;
import com.bub.pay.core.entity.domain.GatewayLog;
import com.bub.pay.framework.common.constant.SystemConstants;
import com.bub.pay.framework.common.entity.model.RespObject;
import com.bub.pay.framework.common.exception.GlobalException;
import com.bub.pay.framework.common.util.IpRemote;
import com.bub.pay.openservice.entity.vo.CommonProtocolVO;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

;

@Aspect
@Component
public class GatewayLogAop {

    private Logger log = LoggerFactory.getLogger(getClass());

    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    @Pointcut(value = "@annotation(com.bub.pay.framework.common.annotation.GatewayLog)")
    public void cutService() {
    }

    @Around("cutService()")
    public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
        // 记录方式执行开始时间
        long beginTime = System.currentTimeMillis();
        GatewayLog gatewayLog = preBuildGatewayLog(point);
        String rspData = null;
        Object result;
        try {
            result = point.proceed();
            if (result instanceof RespObject) {
                rspData = JSON.toJSONString(result);
            } else if (result instanceof String) {
                rspData = result.toString();
            }
        } catch (Throwable e) {
            if (e instanceof GlobalException) {
                GlobalException ge = (GlobalException) e;
                rspData = "业务异常:code=" + ge.getCode() + ",info=" + ge.getInfo();
            } else {
                rspData = "系统异常:" + e.getMessage();
            }
            throw e;
        } finally {
            gatewayLog.setProcessTime(System.currentTimeMillis() - beginTime);
            try {
                log.info("========>响应内容 : |{}", rspData);
                gatewayLog.setRspData(rspData);
//                taskExecutor.execute(() -> gatewayLogService.insertSelective(gatewayLog));
            } catch (Exception e) {
                log.error("记录网关请求日志异常", e);
            }
        }
        return result;
    }

    private GatewayLog preBuildGatewayLog(ProceedingJoinPoint point) {
        Date currDate = new Date();
        GatewayLog gatewayLog = new GatewayLog();
        gatewayLog.setCreateDate(currDate);
        gatewayLog.setUpdateDate(currDate);
        try {
            MethodSignature msig = (MethodSignature) point.getSignature();
            Object target = point.getTarget();
            Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
            com.bub.pay.framework.common.annotation.GatewayLog annotation = currentMethod.getAnnotation(com.bub.pay.framework.common.annotation.GatewayLog.class);
            if (!Objects.isNull(annotation)) {
                gatewayLog.setOperatType(annotation.operatType());
                gatewayLog.setOperatName(annotation.operatorName());
            }
            Object[] args = point.getArgs();
            String[] methodParamNames = discoverer.getParameterNames(currentMethod);
            Map<String, Object> paramsMap = new HashMap<>();
            for (int i = 0; i < methodParamNames.length; i++) {
                Object obj = args[i];
                if (obj instanceof CommonProtocolVO) {
                    paramsMap.put(methodParamNames[i], JSON.toJSONString(obj));
                } else if (obj instanceof String) {
                    paramsMap.put(methodParamNames[i], obj);
                } else if (obj instanceof HttpServletRequest) {
                    HttpServletRequest facade = (HttpServletRequest) obj;
                    String msgIn = facade.getQueryString();
                    if (StringUtils.isEmpty(msgIn)) {
                        msgIn = IOUtils.toString(facade.getInputStream(), SystemConstants.DEFAULT_CODE);
                    }
                    if (StringUtils.isNotEmpty(msgIn)) {
                        facade.setAttribute("msgIn", msgIn);
                        paramsMap.put(methodParamNames[i], msgIn);
                    }
                }
            }
            gatewayLog.setReqData(paramsMap.toString());
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String ipAddr = IpRemote.getIpAddr(request);
            gatewayLog.setReqIp(ipAddr);
            gatewayLog.setReqUrl(request.getRequestURL().toString());
            log.info("========>请求方法: |{}, 请求参数: |{}", annotation.operatorName(), JSON.toJSONString(paramsMap));
        } catch (Exception e) {
            log.error("构造网关日志异常", e);
        }
        return gatewayLog;
    }
}
